/*
 * FreeGLUT Shapes Demo
 *
 * Written by Nigel Stewart November 2003
 *
 * This program is test harness for the sphere, cone 
 * and torus shapes in FreeGLUT.
 *
 * Spinning wireframe and smooth shaded shapes are
 * displayed until the ESC or q key is pressed.  The
 * number of geometry stacks and slices can be adjusted
 * using the + and - keys.
 */

#include <GL/freeglut.h>

#include <stdlib.h>


#define MENU 1
#define JUEGO 2
#define FIN 3
#define VACIO    2010
#define JUGADOR1 2011
#define JUGADOR2 2012

#define GANA 1001
#define PIERDE 1002
#define EMPATA 1003

#define F1    0.9
#define F2    -0.8
#define F3    -2.8

#define C1    -1.4
#define C2    0.05
#define C3    1.4

#define FILA1   0
#define FILA2   1
#define FILA3   2
#define COL1    0
#define COL2    1
#define COL3    2
#define DIAG1   1
#define DIAG2   2

static int slices = 0;
static int menu = MENU; 
static int stacks = 0;
static int circular = 0;
static int cubo = 0;
static int turno = JUGADOR2;
static int estado = PIERDE;

int matriz[3][3];

void inicializarMatriz();
void pintarLineas();
void pintarFichas();
void fcircular(float, float);
void fcubo(float, float);
int evaluar(int);
int evaluarFila(int);
int evaluarColumna(int);
int evaluarDiagonal(int);
void imprimirMatriz();

void pintarLineaVertical(int columna)
{
    switch(columna)
    {
        case COL1:
            glBegin(GL_LINES);
            glVertex3f(C1, F1, 0.0f);
            glVertex3f(C1, F3, 0.0f);
            glEnd();
            
            break;
            
        case COL2:
            glBegin(GL_LINES);
            glVertex3f(C2, F1, 0.0f);
            glVertex3f(C2, F3, 0.0f);
            glEnd();
            
            break;
            
        case COL3:
            glBegin(GL_LINES);
            glVertex3f(C3, F1, 0.0f);
            glVertex3f(C3, F3, 0.0f);
            glEnd();
            
            break;
    }
}

void pintarLineaHorizontal(int fila)
{
    switch(fila)
    {
        case FILA1:
            glBegin(GL_LINES);
            glVertex3f(C1, F1, 0.0f);
            glVertex3f(C3, F1, 0.0f);
            glEnd();
            
            break;
            
        case FILA2:
            glBegin(GL_LINES);
            glVertex3f(C1, F2, 0.0f);
            glVertex3f(C3, F2, 0.0f);
            glEnd();
            
            break;
            
        case FILA3:
            glBegin(GL_LINES);
            glVertex3f(C1, F3, 0.0f);
            glVertex3f(C3, F3, 0.0f);
            glEnd();
            
            break;
    }
}
void pintarLineaDiagonal(int diagonal)
{
    switch(diagonal)
    {
        case DIAG1:
            glBegin(GL_LINES);
            glVertex3f(C1, F1, 0.0f);
            glVertex3f(C3, F3, 0.0f);
            glEnd();
            
            break;
            
        case DIAG2:
            glBegin(GL_LINES);
            glVertex3f(C1, F3, 0.0f);
            glVertex3f(C3, F1, 0.0f);
            glEnd();
            
            break;
            
    }
}
void lineaGanadora()
{
    int i=0;
    for(i = 0; i < 3; i++)
        if(evaluarFila(i))
            pintarLineaHorizontal(i);
            
    for(i = 0; i < 3; i++)
        if(evaluarColumna(i))
            pintarLineaVertical(i);
            
    for(i = DIAG1; i <= DIAG2; i++)
        if(evaluarDiagonal(i))
            pintarLineaDiagonal(i);
}
void inicializarMatriz()
{
    int f, c;    
    for (f = 0; f < 3; f++)
    {
        for (c = 0; c < 3; c++)
        {
            matriz[f][c] = VACIO;
        }
    }
}

int contenidoMatriz()
{
    int f, c, ban=0;
    for (f = 0; f < 3; f++)
    {
        for (c = 0; c < 3; c++)
        {
           if(matriz[f][c] == VACIO)    ban=1;
        }
    }
    
    if(ban==0)  return 1;//si esta lleno
    return 0;//existe algun lugar disponible
}
/*
void inteligenciaRandom()
{
    int f, c;
    srand (time(NULL));
    if(!contenidoMatriz())
    {
        f = rand() % 3;
        c = rand() % 3;
        if(matriz[f][c] != VACIO)
        {
            matriz[f][c] = turno;
            turno = turno == JUGADOR1 ? JUGADOR2 : JUGADOR1;
        }
    }
}
*/
void pintarLineas()
{
    //Linea horizontal de arriba
    glBegin(GL_LINES);
    glVertex3f(-2.0f, 0.0f, 0.0f);
    glVertex3f(2.0f, 0.0f, 0.0f);
    glEnd();
    //Linea horizontal de abajo
    glBegin(GL_LINES);
    glVertex3f(-2.0f, -2.0f, 0.0f);
    glVertex3f(2.0f, -2.0f, 0.0f);
    glEnd();
    //Linea vertical de la izquierda
    glBegin(GL_LINES);
    glVertex3f(-0.8f, 1.5f, 0.0f);
    glVertex3f(-0.8f, -3.5f, 0.0f);
    glEnd();
    //Linea vertical de la derecha
    glBegin(GL_LINES);
    glVertex3f(0.8f, 1.5f, 0.0f);
    glVertex3f(0.8f, -3.5f, 0.0f);
    glEnd();       
}

int evaluar(key)
{
    int asdf = 0;
    
    switch(key)
    {
        case '1':
            asdf += evaluarFila(FILA3);
            asdf += evaluarColumna(COL1);
            asdf += evaluarDiagonal(DIAG1);
            break;
        case '2':
            asdf += evaluarFila(FILA3);
            asdf += evaluarColumna(COL2);
            break;
        case '3':
            asdf += evaluarFila(FILA3);
            asdf += evaluarColumna(COL3);
            asdf += evaluarDiagonal(DIAG2);
            break;
        case '4':
            asdf += evaluarFila(FILA2);
            asdf += evaluarColumna(COL1);
            break;
        case '5':
            asdf += evaluarFila(FILA2);
            asdf += evaluarColumna(COL2);
            asdf += evaluarDiagonal(DIAG1);
            asdf += evaluarDiagonal(DIAG2);
            break;
        case '6':
            asdf += evaluarFila(FILA2);
            asdf += evaluarColumna(COL3);
            break;
        case '7':
            asdf += evaluarFila(FILA1);
            asdf += evaluarColumna(COL1);
            asdf += evaluarDiagonal(DIAG1);
            break;
        case '8':
            asdf += evaluarFila(FILA1);
            asdf += evaluarColumna(COL2);
            break;
        case '9':
            asdf += evaluarFila(FILA1);
            asdf += evaluarColumna(COL3);
            asdf += evaluarDiagonal(DIAG2);
            break;
    }
    
    return asdf;
}

int evaluarFila(int fila)
{
    if (matriz[fila][COL1] == matriz[fila][COL2] &&
        matriz[fila][COL1] == matriz[fila][COL3] &&
        matriz[fila][COL1] != VACIO)
    {
        return 1;   
    }
    return 0;
}

int evaluarColumna(int columna)
{
    if (matriz[FILA1][columna] == matriz[FILA2][columna] &&
        matriz[FILA1][columna] == matriz[FILA3][columna] &&
        matriz[FILA1][columna] != VACIO)
    {
        return 1;   
    }
    return 0;
}

int evaluarDiagonal(int diagonal)
{
    switch(diagonal)
    {
        case DIAG1:
            if (matriz[FILA1][COL1] == matriz[FILA2][COL2] &&
                matriz[FILA1][COL1] == matriz[FILA3][COL3] &&
                matriz[FILA1][COL1] != VACIO)
            {
                return 1;
            }
            break;
        case DIAG2:
            if (matriz[FILA1][COL3] == matriz[FILA2][COL2] &&
                matriz[FILA1][COL3] == matriz[FILA3][COL1] &&
                matriz[FILA1][COL3] != VACIO)
            {
                return 1;
            }
            break;   
    }
    return 0;
}

void pintarTitulo()
{
    glRasterPos3f(-1,3,0);
    glColor4f(0.0f, 1.0f, 0.0f, 0.0f);
    glutBitmapString(GLUT_BITMAP_HELVETICA_18, "TA - TE - TI");   
}

void pintarMensajes()
{
    if(estado == GANA)
    {
        glRasterPos3f(2.5,0,0);
        glColor4f(0.0f, 1.0f, 0.0f, 0.0f);
        glutBitmapString(GLUT_BITMAP_HELVETICA_18, "Fin del juego!!!");
        
        if(turno == JUGADOR2)
        {
            glRasterPos3f(2.5,-1,0);
            glColor4f(0.0f, 1.0f, 0.0f, 0.0f);
            glutBitmapString(GLUT_BITMAP_HELVETICA_18, "Ganador Esfera!");
            lineaGanadora();
        }
        else
        {
            glRasterPos3f(2.5,-1,0);
            glColor4f(0.0f, 1.0f, 0.0f, 0.0f);
            glutBitmapString(GLUT_BITMAP_HELVETICA_18, "Ganador Cubo!");
            lineaGanadora();
        }    
    }
    else
    {
        if(estado == EMPATA && contenidoMatriz())
        {
            glRasterPos3f(2.5,0,0);
            glColor4f(0.0f, 1.0f, 0.0f, 0.0f);
            glutBitmapString(GLUT_BITMAP_HELVETICA_18, "Fin del juego!!!");
            
            glRasterPos3f(2.5,-1,0);
            glColor4f(0.0f, 1.0f, 0.0f, 0.0f);
            glutBitmapString(GLUT_BITMAP_HELVETICA_18, "Empate!!");
        }
    }  
}

void pintarFichas()
{
    int f, c;
    float X, Y;
    
    glPushMatrix();
    
        for (f = 0; f < 3; f++)
        {
            switch (f)
            {
                case 0:
                    Y = F1;
                    break;
                case 1:
                    Y = F2;
                    break;
                case 2:
                    Y = F3;
                    break;
            }
            
            for (c = 0; c < 3; c++)
            {
                switch (c)
                {
                    case 0:
                        X = C1;
                        break;
                    case 1:
                        X = C2;
                        break;
                    case 2:
                        X = C3;
                        break;
                }
                
                //pintar
                switch(matriz[f][c])
                {
                    case JUGADOR1:
                        fcircular(X, Y);
                        break;
                    case JUGADOR2:
                        fcubo(X, Y);
                        break;
                    default:
                        break;
                }
            }
        }
    glPopMatrix();
}

/* GLUT callback Handlers */
void fcircular( float x, float y)
{
     glColor3d(0,1,1);
     glPushMatrix();
         glTranslated(x,y,0);
         glutSolidSphere(0.5,15,15);
     glPopMatrix();  
}

void fcubo(float x, float y)
{
     glColor3d(1,1,0);
     glPushMatrix();
         glTranslated(x,y,0);
         glutSolidCube(1);
     glPopMatrix();  
}

static void 
resize(int width, int height)
{
    const float ar = (float) width / (float) height;
    
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(1, -1, -1.0, 1.0, 2.0, 100.0);
    gluLookAt(0,0,-10 ,0,0,0 ,0,1,0);//agregamos
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
}

static void 
display(void)
{
    const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
    const double a = t*90.0;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3d(1,0,0);
    
    pintarTitulo();
    
    switch(menu)
    {
        case MENU:{
            glRasterPos3f(-0.5,0,0);
            glutBitmapString(GLUT_BITMAP_HELVETICA_18, "PLAY (Enter)");
        }
        break;
        case JUEGO:{
            pintarLineas();
            
            pintarFichas();
        }
        break;
        case FIN:{
            pintarLineas();
            
            pintarFichas();
            
            pintarMensajes();
        }
        break;
    }    
    glutSwapBuffers();
}


static void 
key(unsigned char key, int x, int y)
{
    switch (menu)
    {
        case MENU:
            switch (key) 
            {
                case 13:
                     menu = JUEGO;
                     turno = JUGADOR1;
                     break;
                case 'q':
                    exit(0);
                    break;
            }
            break;
        case JUEGO:
             switch(key)
             {
                case 'q':
                    exit(0);
                    break;
                case '1':
                    if (matriz[2][0] == VACIO)
                    {
                        matriz[2][0] = turno;
                        turno = turno == JUGADOR1 ? JUGADOR2 : JUGADOR1;
                        if (evaluar(key) > 0)
                        {
                            estado = GANA;
                        }
                        else estado = EMPATA;
                        
                        //movimiento random
                        //inteligenciaRandom();
                    }
                    break;
                case '2':
                    if (matriz[2][1] == VACIO)
                    {
                        matriz[2][1] = turno;
                        turno = turno == JUGADOR1 ? JUGADOR2 : JUGADOR1;
                        
                        if (evaluar(key) > 0)
                        {
                            estado = GANA;
                        }
                        else 
                            estado = EMPATA;
                        //movimiento random
                        //inteligenciaRandom();
                    }
                    break;
                case '3':
                    if (matriz[2][2] == VACIO)
                    {
                        matriz[2][2] = turno;
                        turno = turno == JUGADOR1 ? JUGADOR2 : JUGADOR1;
                        if (evaluar(key) > 0){estado = GANA;}
                        else estado = EMPATA;
                        //movimiento random
                        //inteligenciaRandom();
                    }
                    break;
                case '4':
                    if (matriz[1][0] == VACIO)
                    {
                        matriz[1][0] = turno;
                        turno = turno == JUGADOR1 ? JUGADOR2 : JUGADOR1;
                        if (evaluar(key) > 0){estado = GANA;}
                        else estado = EMPATA;
                        //movimiento random
                        //inteligenciaRandom();
                    }
                    break;
                case '5':
                    if (matriz[1][1] == VACIO)
                    {
                        matriz[1][1] = turno;
                        turno = turno == JUGADOR1 ? JUGADOR2 : JUGADOR1;
                        if (evaluar(key) > 0){estado = GANA;}
                        else estado = EMPATA;
                        //movimiento random
                        //inteligenciaRandom();
                    }
                    break;
                case '6':
                    if (matriz[1][2] == VACIO)
                    {
                        matriz[1][2] = turno;
                        turno = turno == JUGADOR1 ? JUGADOR2 : JUGADOR1;
                        if (evaluar(key) > 0){estado = GANA;}
                        else estado = EMPATA;
                        //movimiento random
                        //inteligenciaRandom();
                    }
                    break;
                case '7':
                    if (matriz[0][0] == VACIO)
                    {
                        matriz[0][0] = turno;
                        turno = turno == JUGADOR1 ? JUGADOR2 : JUGADOR1;
                        if (evaluar(key) > 0){estado = GANA;}
                        else estado = EMPATA;
                        //movimiento random
                        //inteligenciaRandom();
                    }
                    break;
                case '8':
                    if (matriz[0][1] == VACIO)
                    {
                        matriz[0][1] = turno;
                        turno = turno == JUGADOR1 ? JUGADOR2 : JUGADOR1;
                        if (evaluar(key) > 0){estado = GANA;}
                        else estado = EMPATA;
                        //movimiento random
                        //inteligenciaRandom();
                    }
                    break;
                case '9':
                    if (matriz[0][2] == VACIO)
                    {
                        matriz[0][2] = turno;
                        turno = turno == JUGADOR1 ? JUGADOR2 : JUGADOR1;
                        if (evaluar(key) > 0){estado = GANA;}
                        else estado = EMPATA;
                        //movimiento random
                        //inteligenciaRandom();
                    }
                    break;
             }
             
            if (estado == GANA)
            {
                menu = FIN;
            }
             
        case FIN:
            switch(key)
            {
                case 'q':
                    exit(0);
                    break;
            }
        default :
            switch(key)
            {
                case 'q':
                    exit(0);
                    break;
            }  
    }
    glutPostRedisplay();
}

static void 
idle(void)
{
    glutPostRedisplay();
}

const GLfloat light_ambient[]  = { 0.0f, 0.0f, 0.0f, 1.0f };
const GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };

const GLfloat mat_ambient[]    = { 0.7f, 0.7f, 0.7f, 1.0f };
const GLfloat mat_diffuse[]    = { 0.8f, 0.8f, 0.8f, 1.0f };
const GLfloat mat_specular[]   = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat high_shininess[] = { 100.0f };

/* Program entry point */

int 
main(int argc, char *argv[])
{
    inicializarMatriz();

    glutInit(&argc, argv);
    glutInitWindowSize(640,480);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("FreeGLUT Shapes");

    glutReshapeFunc(resize);
    glutDisplayFunc(display);
    glutKeyboardFunc(key);
    glutIdleFunc(idle);

    glClearColor(1,1,1,1);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    glEnable(GL_LIGHT0);
    glEnable(GL_NORMALIZE);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING);

    glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);

    glutMainLoop();

    return EXIT_SUCCESS;
}

